package com.base.cn.platform.os.service.classes.member;

import com.base.cn.platform.os.common.mybatis.BaseBiz;
import com.base.cn.platform.os.common.mybatis.Pagination;
import com.base.cn.platform.os.common.utils.DataUtil;
import com.base.cn.platform.os.common.utils.ObjectUtils;
import com.base.cn.platform.os.common.utils.StringUtils;
import com.base.cn.platform.os.common.utils.result.ResultUtil;
import com.base.cn.platform.os.dao.classes.member.ClassesMemberDao;
import com.base.cn.platform.os.entity.classes.Classes;
import com.base.cn.platform.os.entity.classes.condition.ClassesMemberCondition;
import com.base.cn.platform.os.entity.classes.member.ClassesMember;
import com.base.cn.platform.os.service.classes.ClassesBiz;
import com.base.cn.platform.os.service.manage.sysUser.SysUserService;
import com.base.cn.platform.os.service.manage.teacher.SysTeacherService;
import com.base.cn.platform.os.service.manage.user.user.CusUserService;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.RequestParam;

import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
import java.util.stream.Stream;

/**
 * 班级成员
 *
 * @author SK
 * @since 2018-05-10
 */
@Service
public class ClassesMemberBiz extends BaseBiz<ClassesMember, ClassesMemberDao> {

    @Autowired
    private ClassesBiz classesBiz;
    @Autowired
    private CusUserService cusUserService;
    @Autowired
    private ClassesMemberDao classesMemberDao;
    @Autowired
    private SysTeacherService sysTeacherService;
    @Autowired
    private SysUserService sysUserService;

    /**
     * 获取用户加入了几个班级
     * @param userId  用户ID
     * @return 班级数量
     */
    public BigDecimal countMemberClasses(BigDecimal userId) {
        ClassesMemberCondition condition = new ClassesMemberCondition();
        condition.setMemberId(userId);
        condition.identities(1, 2);
        condition.setStatus(1);
        List<ClassesMember> conditionsList = this.findClassesMemberList(condition,false);
        StringBuffer stringBuffer = new StringBuffer();
        conditionsList.forEach(e -> {
            stringBuffer.append(e.getClassesId()).append(",");
        });
        String classesIds = StringUtils.subHeadTailString(stringBuffer.toString(),",");
        if(!StringUtils.isNotEmpty(classesIds)){
            return new BigDecimal(0);
        }
        List<Classes> classesList = classesBiz.find(" id in("+classesIds+") and status = 1",null,null);
        return new BigDecimal(classesList.size());
    }

    /**
     * 根据班级id查询班级成员
     *
     * @param classesIds 班级id
     * @param setMember  设置成员
     * @param order      排序 1.班主任 -> 普通学员
     * @param identity   1.普通学员 2.班级管理员 3.班主任
     * @return 班级成员 key:班级id value:班级成员
     */
    public Map<BigDecimal, List<ClassesMember>> findClassesMemberByClassesIds(String classesIds, boolean setMember,
                                                                              Integer order, int... identity) {
        ClassesMemberCondition condition = new ClassesMemberCondition();
        condition.setClassesIds(classesIds);
        condition.setOrder(order);
        condition.setIdentities(identity);
        String where = this.where(condition);
        List<ClassesMember> classesMemberList = find(where, null, null);
        this.setMember(classesMemberList, setMember);
        return DataUtil.grouping(classesMemberList, ClassesMember::getClassesId);
    }

    /**
     * 查询班级成员列表
     *
     * @param condition 班级成员查询条件
     * @param setMember 设置成员
     * @return 班级成员列表
     */
    public List<ClassesMember> findClassesMemberList(ClassesMemberCondition condition, boolean setMember) {
        String where = this.where(condition);
        List<ClassesMember> memberList = find(where, condition.getCount(), null);
        this.setMember(memberList, setMember);
        return memberList;
    }

    /**
     * 查询班级成员列表
     *
     * @param condition  班级成员查询条件
     * @param pagination 分页
     * @param setMember  设置成员
     * @return 班级成员列表
     */
    public PageInfo<ClassesMember> findClassesMemberPage(ClassesMemberCondition condition, Pagination pagination, boolean setMember) {
        String where = this.where(condition);
        // 根据用户的手机/邮箱/登录名查询
        if (StringUtils.isNotEmpty(condition.getSearch())) {
            List<ClassesMember> list = find(where, null, null);
            if (ObjectUtils.isEmpty(list)) {
                return new PageInfo<>();
            }
            String cusUserIds = DataUtil.joining(list, ClassesMember::getMemberId);
            Map<String, Object> params = new HashMap<>(2);
            params.put("ids", cusUserIds);
            params.put("keyWord", condition.getSearch());
            List<Map<String, Object>> cusUserList = cusUserService.queryUserList(params, false, false, false, false, false, false, false);
            String memberIds = DataUtil.joining(cusUserList, (v) -> v.get("id"));
            if (StringUtils.isEmpty(memberIds)) {
                return new PageInfo<>();
            }
            where += " and memberId in (" + memberIds + ")";
        }
        PageInfo<ClassesMember> pageInfo = findPage(where, pagination, null);
        this.setMember(pageInfo.getList(), setMember);
        return pageInfo;
    }

    /**
     * 查询用户的班级列表 分页
     * @param classesMember 查询条件
     * @return PageInfo<Classes>
     */
    public PageInfo<Classes> findClassesPersonalListPage(Pagination page,
                                                  ClassesMember classesMember){
        PageHelper.startPage(page.getCurrentPage(),page.getPageSize());
        Page<Classes> classesPage = classesMemberDao.findClassesPersonalListPage(ClassesMember.class,classesMember);
        PageInfo<Classes> classesPageInfo = new PageInfo<>(classesPage);
        return classesPageInfo;
    }

    /**
     * 查询用户的班级列表 不分页
     * @param classesMember 查询条件
     * @return PageInfo<Classes>
     */
    public List<Classes> findClassesPersonalList(ClassesMember classesMember){
        return classesMemberDao.findClassesPersonalList(ClassesMember.class,classesMember);
    }

    /**
     * 是否加入班级
     *
     * @param classesId 班级id
     * @param memberId  班级成员的id
     * @return {@code true}加入，否则返回{@code false}
     */
    public boolean isJoined(BigDecimal classesId, BigDecimal memberId) {
        if (DataUtil.idIsNotNull(memberId)) {
            ClassesMemberCondition condition = new ClassesMemberCondition();
            condition.setClassesId(classesId);
            condition.setMemberId(memberId);
            condition.identities(1, 2);
            String where = this.where(condition);
            ClassesMember one = findOne(where, null);
            return Objects.nonNull(one);
        }
        return false;
    }

    /**
     * 是否已被封禁
     *
     * @param classesId 班级id
     * @param memberId  班级成员的id
     * @return {@code true}未被封禁，否则返回{@code false}
     * @return
     */
    public boolean isBanned(BigDecimal classesId, BigDecimal memberId) {
        if (ObjectUtils.isNotEmpty(memberId)) {
            ClassesMemberCondition condition = new ClassesMemberCondition();
            condition.setClassesId(classesId);
            condition.setMemberId(memberId);
            condition.identities(1, 2);
            condition.setStatus(2);
            String where = this.where(condition);
            ClassesMember one = findOne(where, null);
            return !(ObjectUtils.isNotEmpty(one) && one.getStatus() == 2);
        }
        return false;
    }

    /**
     * 保存班级成员
     *
     * @param classesId 班级id
     * @param memberIds 成员id
     * @param identity  1.普通学员 2.班级管理员 3.班主任
     */
    @Transactional(rollbackFor = Exception.class)
    public Map<String, Object> saveClassesMemberBatch(BigDecimal classesId, String memberIds, Integer identity, Integer source) {
        Classes classes = classesBiz.findById(classesId);
        if(classes.getStatus() == 1){
            List<ClassesMember> databaseList = this.getClassesMember(classes, memberIds, identity);
            // 前台用户触发的加入班级操作，禁止加入同一课程的多个班级
            if (source == 1 && ObjectUtils.isNotEmpty(databaseList)) {
                Map<String, Object> map = new HashMap<>();
                map.put("status",5);
                return ResultUtil.ERROR("已加入同课程其他班级",map);
            }
            Map<BigDecimal, ClassesMember> databaseMap = DataUtil.toMap(databaseList, ClassesMember::getMemberId);
            BigDecimal courseId = classes.getCourseId();
            List<ClassesMember> classesMemberList = Stream.of(memberIds.split(","))
                    .map((v) -> {
                        BigDecimal memberId = new BigDecimal(v);
                        ClassesMember member = databaseMap.get(memberId);
                        return this.createIfAbsent(member, memberId, classesId, courseId, identity);
                    })
                    .collect(Collectors.toList());
            Map<BigDecimal, Long> refresh = DataUtil.counting(databaseList, ClassesMember::getClassesId);
            // 新导入班级成员中，数据库中已存在数
            Long databaseCount = databaseList.stream().filter((v) -> v.getClassesId().equals(classesId)).count();
            // 新导入班级成员数(不含已加入)
            if(classesMemberList.size() - databaseCount == 0){
                if(identity==3){
                    return ResultUtil.ERROR("所选教师已添加");
                }else{
                    return ResultUtil.ERROR("所选学员已添加");
                }
            }
            if(identity==3){
                List<ClassesMember> teacherList = this.getClassesMember(classes, null, 3);
                //班主任数量 teacherChargeSize;
                int teacherChargeSize =0;
                for (ClassesMember classesMember: teacherList) {

                    if(classesMember.getIdentity()==3){
                        teacherChargeSize+=1;
                    }
                }
                String[] teachersIds = memberIds.split(",");
                if(teacherChargeSize>=3||teachersIds.length>3){
                    return ResultUtil.ERROR("最多添加3位班主任");
                }
            }

            refresh.put(classesId, classesMemberList.size() - databaseCount);
            Map<String, Object> result = classesBiz.refreshAndUpdateClasses(refresh, identity);
            if (result != null) {
                return result;
            }
            // 新增/更新分组
            Map<Boolean, List<ClassesMember>> classesMemberMap = DataUtil.grouping(classesMemberList, (v) -> DataUtil.idIsNotNull(v.getId()));
            List<ClassesMember> batch = classesMemberMap.get(true);
            if (ObjectUtils.isNotEmpty(batch)) {
                updateBatch(batch);
            }
            batch = classesMemberMap.get(false);
            if (ObjectUtils.isNotEmpty(batch)) {
                batchSave(batch);
            }
            String message = identity == 3 ? "保存班级班主任成功" : "保存班级成员成功";
            HashMap<Object, Object> objectObjectHashMap = new HashMap<>();
            objectObjectHashMap.put("memberId",DataUtil.joining(batch, ClassesMember::getMemberId));
            return ResultUtil.SUCCESS(message, objectObjectHashMap);
        }else {
            return ResultUtil.ERROR("班级暂未成立或已停班，无法加入");
        }
    }

    /**
     * 更新班级成员身份
     *
     * @param ids      班级成员id
     * @param identity 1.普通学员 2.班级管理员 3.班主任
     * @return 操作结果
     */
    public Map<String, Object> updateClassesMemberIdentity(@RequestParam("ids") String ids,
                                                           @RequestParam("identity") Integer identity) {
        String where = " id in (" + ids + ") and identity != 3";
        ClassesMember classesMember = new ClassesMember();
        classesMember.setIdentity(identity);
        updateByWhereSql(classesMember, where);
        return ResultUtil.SUCCESS("更新班级成员身份成功");
    }

    /**
     * 更新班级成员状态
     *
     * @param ids    班级成员id
     * @param status 1.正常 2.封禁
     * @return 操作结果
     */
    public Map<String, Object> updateClassesMemberStatus(String ids, int status) {
        String where = " id in (" + ids + ") and identity != 3";
        ClassesMember classesMember = new ClassesMember();
        classesMember.setStatus(status);
        updateByWhereSql(classesMember, where);
        return ResultUtil.SUCCESS("更新班级成员状态成功");
    }

    /**
     * 检测用户是否有购买，且未加入的班级
     * @param userId 用户ID
     * @return true有，false没有
     */
    public boolean checkNoJoinClassesMember(BigDecimal userId){
        Integer count = classesMemberDao.checkNoJoinClassesMember(ClassesMember.class,userId);
        if(ObjectUtils.isEmpty(count) || count.intValue() ==0){
            return false;
        }
        return true;
    }
    //===============================================================================
    /**
     * 查询班级成员
     *
     * @param classes   班级
     * @param memberIds 成员ids
     * @param identity  1.普通学员 2.班级管理员 3.班主任
     * @return 班级成员
     */
    private List<ClassesMember> getClassesMember(Classes classes, String memberIds, int identity) {
        List<ClassesMember> databaseList = new LinkedList<>();
        // 同班级
        ClassesMemberCondition condition = new ClassesMemberCondition();
        String where = "";
        // 同课程不同班级 忽略保存班主任或自由班级的情况
        if (!(identity == 3 || classes.isFree())) {
            condition = new ClassesMemberCondition();
            condition.setCourseId(classes.getCourseId());
            condition.setMemberIds(memberIds);
            condition.identities(1, 2);
            where += this.where(condition);
            where += " and status != 3";
            databaseList.addAll(find(where, null, null));
        }else{
            condition.setClassesId(classes.getId());
            if (identity == 3) {
                condition.identities(identity);
            } else {
                condition.identities(1, 2);
            }
            condition.setMemberIds(memberIds);
            where += this.where(condition);
            databaseList.addAll(find(where, null, null));
        }
        return databaseList;
    }

    /**
     * 构造班级成员记录
     *
     * @param container 班级成员 若数据库不存在指定courseId或classesId与memberId的班级成员时为null
     * @param memberId  成员id(对应用户id)
     * @param classesId 班级id
     * @param courseId  课程id
     * @param identity  1.普通学员 2.班级管理员 3.班主任
     * @return 班级成员
     */
    private ClassesMember createIfAbsent(ClassesMember container, BigDecimal memberId, BigDecimal classesId,
                                         BigDecimal courseId, Integer identity) {
        if (container == null) {
            container = new ClassesMember();
        }
        container.setClassesId(classesId);
        container.setCourseId(courseId);
        container.setIdentity(identity);
        container.setMemberId(memberId);
        container.setStatus(1);
        return container;
    }

    /**
     * 设置班级成员
     *
     * @param classesMemberList 班级成员
     * @param setMember         设置成员
     */
    private void setMember(List<ClassesMember> classesMemberList, boolean setMember) {
        if (setMember && ObjectUtils.isNotEmpty(classesMemberList)) {
            //用户ID串
            String cusUserIds = DataUtil.joining(classesMemberList, (v) -> v.getIdentity() != 3 ? v.getMemberId() : null);
            Map<BigDecimal, Map<String, Object>> cusUserMap = this.getCusUserMap(cusUserIds);
            //老师ID串
            String teacherIds = DataUtil.joining(classesMemberList, (v) -> v.getIdentity() == 3 ? v.getMemberId() : null);
            Map<BigDecimal, Map<String, Object>> teacherMap = this.getTeacherMap(teacherIds);
            classesMemberList.forEach((v) -> {
                Map<String, Object> member = v.getIdentity() == 3 ?teacherMap.get(v.getMemberId()) :cusUserMap.get(v.getMemberId());
                v.setMember(member);
            });
            StringBuffer stringBuffer = new StringBuffer();
            List<ClassesMember> _list = new LinkedList<>();
            IntStream.range(0,classesMemberList.size()).forEach(index->{
                ClassesMember classesMember = classesMemberList.get(index);
                Map<String,Object> member = classesMember.getMember();
                if(ObjectUtils.isEmpty(member)){
                    stringBuffer.append(classesMember.getId()).append(",");
                }else{
                    _list.add(classesMemberList.get(index));
                }
            });
            classesMemberList.clear();
            classesMemberList.addAll(_list);
            String meIds = StringUtils.subHeadTailString(stringBuffer.toString(),",");
            if(StringUtils.isNotEmpty(meIds)){
                this.deleteWhereSql("id in ("+meIds+")");
            }
        }
    }

    /**
     * 根据id查询前台用户
     *
     * @param ids 用户id
     * @return 前台用户 key:前台用户id value:前台用户
     */
    public Map<BigDecimal, Map<String, Object>> getCusUserMap(String ids) {
        if (ids.isEmpty()) {
            return Collections.emptyMap();
        }
        Map<BigDecimal, Map<String, Object>> cusUserMap;
        cusUserMap = cusUserService.queryCusUserMapByUserIds(ids, false, false, false, false, false, false, false);
        return cusUserMap == null ? Collections.emptyMap() : cusUserMap;
    }

    /**
     * 根据id查询教师
     *
     * @param teacherIds 老师ID串
     * @return 后台用户 key:后台用户id value:后台用户
     */
    public Map<BigDecimal, Map<String, Object>> getTeacherMap(String teacherIds) {
        if (teacherIds.isEmpty()) {
            return Collections.emptyMap();
        }
        Map<BigDecimal, Map<String, Object>> sysUserMap = sysTeacherService.findSysTeacherToMapByIds(teacherIds,false,false,false,false,false);
        return sysUserMap == null ? Collections.emptyMap() : sysUserMap;
    }
    /**
     * 根据id查询后台用户
     *
     * @param ids 用户id
     * @return 后台用户 key:后台用户id value:后台用户
     */
    public Map<BigDecimal, Map<String, Object>> getSysUserMap(String ids) {
        if (ids.isEmpty()) {
            return Collections.emptyMap();
        }
        Map<BigDecimal, Map<String, Object>> sysUserMap = sysUserService.findSysUserMapByUserIds(ids, false, false, false);
        return sysUserMap == null ? Collections.emptyMap() : sysUserMap;
    }

    public  Map<String,Object> deleteClassTeacher(BigDecimal id){
        String where = " id in (" + id + ") and identity != 4";
        ClassesMember classesMember = new ClassesMember();
        classesMember.setStatus(4);
        updateByWhereSql(classesMember, where);
        return ResultUtil.SUCCESS("删除班主任成功");
    }
    /**
     * 拼接查询班级成员的where子句
     *
     * @param condition 查询条件
     * @return where子句
     */
    private String where(ClassesMemberCondition condition) {
        String where = " status != 4";
        if (StringUtils.isNotEmpty(condition.getClassesIds())) {
            where += " and classesId in (" + condition.getClassesIds() + ")";
        } else if (DataUtil.idIsNotNull(condition.getClassesId())) {
            where += " and classesId = " + condition.getClassesId();
        }
        if (DataUtil.idIsNotNull(condition.getCourseId())) {
            where += " and courseId = " + condition.getCourseId();
        }
        if (StringUtils.isNotEmpty(condition.getMemberIds())) {
            where += " and memberId in (" + condition.getMemberIds() + ")";
        } else if (DataUtil.isPositive(condition.getMemberId())) {
            where += " and memberId = " + condition.getMemberId();
        }
        if (condition.getIdentities() != null && condition.getIdentities().length > 0) {
            int[] identities = condition.getIdentities();
            StringJoiner joiner = new StringJoiner(",");
            for (int identity : identities) {
                joiner.add(identity + "");
            }
            where += " and identity in (" + joiner + ")";
        } else if (DataUtil.isPositive(condition.getIdentity())) {
            where += " and identity = " + condition.getIdentity();
        }
        if (DataUtil.isNonNegative(condition.getStatus())) {
            where += " and status = " + condition.getStatus();
        }
        if (DataUtil.isPositive(condition.getOrder())) {
            where += " order by identity desc";
        }
        return where;
    }
}
